package com.uw.uwconfig.client.value;

import com.uw.uwconfig.client.util.FieldUtil;
import com.uw.uwconfig.client.util.PlaceholderHelper;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import java.lang.reflect.Field;
import java.util.List;


/**
 * 用于订阅处理 @Value 属性的更新。
 * <p>
 * 1. 缓存标记 @Value 的字段信息。
 * 2. 通过反射更新 @Value 字段信息。
 */
@Slf4j
@Setter
public class SpringValueBeanPostProcessor implements BeanPostProcessor, ApplicationListener<EnvironmentChangeEvent>, BeanFactoryAware {

    private BeanFactory beanFactory;


    private static final MultiValueMap<String, SpringValueMeta> VALUE_MAP = new LinkedMultiValueMap<>();

    /**
     * 缓存标记 @Value 的字段信息。
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        for (Field field : FieldUtil.getAnnotationFieldList(bean.getClass(), Value.class)) {
            log.info("[UwConfig] >> find spring value field: {}", field);
            Value valueAnnotation = field.getAnnotation(Value.class);
            for (String placeholderKey : PlaceholderHelper.getInstance().extractPlaceholderKeys(valueAnnotation.value())) {
                log.info("[UwConfig] >> find spring value key: {}", placeholderKey);
                SpringValueMeta springValueMeta = new SpringValueMeta(bean, beanName, placeholderKey, valueAnnotation.value(), field);
                VALUE_MAP.add(placeholderKey, springValueMeta);
            }
        }

        return bean;
    }


    /**
     * 通过反射更新 @Value 字段信息。
     */
    @Override
    public void onApplicationEvent(EnvironmentChangeEvent event) {
        for (String key : event.getKeys()) {
            log.debug("[UwConfig] >> Spring value key:{}", key);
            List<SpringValueMeta> springValueMetas = VALUE_MAP.get(key);
            if (CollectionUtils.isEmpty(springValueMetas)) {
                continue;
            }

            for (SpringValueMeta springValueMeta : springValueMetas) {
                Object fieldValue = PlaceholderHelper.getInstance().resolvePropertyValue((ConfigurableBeanFactory) beanFactory, springValueMeta.getBeanName(), springValueMeta.getPlaceholder());
                log.debug("[UwConfig] >> Spring value springValueMeta:{} with value:{}", springValueMeta, fieldValue);
                springValueMeta.getField().setAccessible(true);
                try {
                    springValueMeta.getField().set(springValueMeta.getBean(), fieldValue);
                } catch (IllegalAccessException ex) {
                    log.error("[UwConfig] >> update spring value error", ex);
                }
            }
        }
    }
}
